package cn.xeblog.plugin.game.chess;

import cn.xeblog.commons.entity.User;
import cn.xeblog.commons.entity.game.chess.ChessDTO;
import cn.xeblog.commons.enums.Game;
import cn.xeblog.plugin.annotation.DoGame;
import cn.xeblog.plugin.cache.DataCache;
import cn.xeblog.plugin.game.AbstractGame;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.ui.JBColor;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 中国象棋入口
 * 作者：Hao.<br>
 */
@DoGame(Game.CHINESE_CHESS)
public class ChineseChess extends AbstractGame<ChessDTO> {

    /**
     * 开始界面
     */
    private JPanel startPanel;

    /**
     * 游戏界面
     */
    private GamePanel gamePanel;

    // ----------------  开始界面 组件  ----------------
    /**
     * 对战方式
     */
    private JComboBox<String> jcb_fightType;
    /**
     * 玩家所属阵营列表（红方、黑方）
     */
    private JComboBox<String> jcb_playFirst;
    /**
     * 玩家界面类型
     */
    private JComboBox<String> jcb_UIType;
    /**
     * 中国象棋缓存
     */
    ChessCache chessCache;
    /**
     * 游戏状态 -2.初始化 -1.待开始 0.进行中 1.赢 2.平
     */
    int status = -2;

    @Override
    protected void start() {
        // 在线模式-游戏开始
        startGame0(ChessCache.Mode.ONLINE);
    }

    @Override
    protected void init() {
        // 启用主界面并设置可见、最小尺寸
        this.mainPanel.removeAll();
        this.mainPanel.setLayout(null);
        this.mainPanel.setEnabled(true);
        this.mainPanel.setVisible(true);
        this.mainPanel.setMinimumSize(new Dimension(150, 400));

        // 开始面板设置
        this.startPanel = new JPanel();
        this.startPanel.setBounds(10, 10, 120, 400);

        // 构建开始面板
        this.startPanel();

        // 刷新界面
        this.mainPanel.add(startPanel);
        this.mainPanel.updateUI();
    }

    @Override
    protected void allPlayersGameStarted() {
        // 当前所属阵营
        boolean currentPlayer = !chessCache.currentPlayer;
        // 对方所属阵营
        boolean opposingPlayer = !currentPlayer;

        // 当前界面
        ChessDTO.UI currentUI = Arrays.stream(ChessDTO.UI.values()).filter(o -> o.getName().equals(jcb_UIType.getSelectedItem().toString())).findFirst().get();
        // 房主
        if (isHomeowner()) {
            // 自旋等待一段时间，再发送游戏数据
            invoke(() -> {
                ChessDTO msg = new ChessDTO();
                msg.setType(opposingPlayer);
                msg.setCurrentUI(currentUI);
                sendMsg(msg);
                handle(new ChessDTO(0, 0, currentPlayer, -1, ChessDTO.Option.DEFAULT, currentUI));
            }, 500);
        }
    }

    @Override
    public void handle(ChessDTO body) {
        gamePanel.jb_undo.setEnabled(false);
        if (status > -1) {
            // 对方悔棋
            if (body.getOption().equals(ChessDTO.Option.UNDO)) {
                int i = JOptionPane.showConfirmDialog(gamePanel, "对方请求悔棋，是否同意？", "提示", JOptionPane.YES_NO_OPTION);
                if (i != 0) {
                    // 拒绝悔棋，需发送拒绝通知
                    send(new Point(ChessDTO.Option.UNDO_REJECT));
                    return;
                }
                chessCache.put = true;
                // 同意悔棋
                send(new Point(ChessDTO.Option.UNDO_CONSENT));
                gamePanel.otherSideUndo();
                return;
            }
            if (body.getOption().equals(ChessDTO.Option.UNDO_REJECT)) {
                gamePanel.jb_surrender.setEnabled(true);
                JOptionPane.showMessageDialog(gamePanel, "对方拒绝悔棋！");
                return;
            }
            if (body.getOption().equals(ChessDTO.Option.UNDO_CONSENT)) {
                gamePanel.jb_surrender.setEnabled(true);
                chessCache.put = false;
                gamePanel.gameLogic.undo();
                return;
            }
            // 游戏结束，对方投降
            if (body.getOption().equals(ChessDTO.Option.SURRENDER)) {
                JOptionPane.showMessageDialog(gamePanel, "对方投降了！");
                gamePanel.gameOver();
                return;
            }
            // 游戏结束
            if (body.getOption().equals(ChessDTO.Option.GAME_OVER)) {
                JOptionPane.showMessageDialog(gamePanel, "胜败乃兵家常事，少侠请重新来过！");
                gamePanel.gameOver();
                return;
            }

            // 另一方检查，即”将军“
            if (body.getOption().equals(ChessDTO.Option.CHECK)) {
                gamePanel.otherSideCheck();
            }

            // 改变玩家信息
            changePlayer(body);
            // 设置棋子
            gamePanel.setChess(new Point(body.getX(), body.getY(), body.isType(), body.getIndex()));

            // 游戏结束，跳出
            if (gamePanel.isGameOver) {
                return;
            }
        } else {
            // 状态变为进行中，在线人人对战，同时红方状态文本改为“思考中”
            status = 0;
            chessCache.currentMode = ChessCache.Mode.ONLINE;
            chessCache.currentBattle = ChessCache.Battle.PVP;
            chessCache.currentUI = body.getCurrentUI();
            this.gamePanel.jlb_redStateText.setText("思考中");

            // 黑方初始化棋盘,变更当前玩家阵营且已落子
            if (!body.isType()) {
                chessCache.currentPlayer = false;
                gamePanel.initChess();
                chessCache.put = true;
                return;
            } else {
                // 设置当前玩家为红方
                chessCache.currentPlayer = true;
            }
        }
        // 当前未落子
        chessCache.put = false;
    }

    /**
     * 开始游戏
     *
     * @param mode 在线/离线模式
     * @return void
     * @author Hao.
     * @date 2022/9/5 10:09
     */
    private void startGame0(ChessCache.Mode mode) {
        // -1.待开始
        status = -1;
        // 中国象棋全局缓存
        chessCache = new ChessCache();

        if (mode == ChessCache.Mode.OFFLINE) {
            // 离线，设置界面类型、对战方式、玩家颜色
            chessCache.currentMode = ChessCache.Mode.OFFLINE;
            ChessCache.Player player = Arrays.stream(ChessCache.Player.values()).filter(o -> o.getName().equals(jcb_playFirst.getSelectedItem().toString())).findFirst().get();
            chessCache.currentPlayer = player.equals(ChessCache.Player.RED.getName()) ? true : false;
            chessCache.currentBattle = Arrays.stream(ChessCache.Battle.values()).filter(o -> o.getName().equals(jcb_fightType.getSelectedItem().toString())).findFirst().get();
            chessCache.currentUI = Arrays.stream(ChessDTO.UI.values()).filter(o -> o.getName().equals(jcb_UIType.getSelectedItem().toString())).findFirst().get();
        }

        // 构建主窗口大小
        mainPanel.removeAll();
        mainPanel.setLayout(new BorderLayout());
        mainPanel.setMinimumSize(new Dimension(320, 360));

        // 添加游戏面板
        this.gamePanel = new GamePanel(this);
        mainPanel.add(gamePanel);

        // 离线模式时
        if (mode == ChessCache.Mode.OFFLINE) {
            // 未落子，且无限悔梅
            chessCache.put = false;
            gamePanel.remove(gamePanel.jb_surrender);
            gamePanel.add(gamePanel.exitButton());
        }

        // 刷新界面
        mainPanel.updateUI();
    }

    /**
     * 发送点位
     *
     * @param point 点位
     */
    public void send(Point point) {
        ChessDTO dto = new ChessDTO();
        dto.setX(point.x);
        dto.setY(point.y);
        dto.setType(point.type);
        dto.setIndex(point.index);
        dto.setOption(point.option);
        sendMsg(dto);
    }

    /**
     * 右边功能区布局<br>
     */
    private void startPanel() {
        // logo图片
        ImageIcon imageIconLogo = new ImageIcon(new ImageIcon(this.getClass().getResource("/games/chinese-chess/logo.png")).getImage().getScaledInstance(100, 50, Image.SCALE_SMOOTH));//缩放图片来适应标签大小
        JLabel labelLogo = new JLabel(imageIconLogo);
        startPanel.add(labelLogo);

        // 界面类型
        JLabel jlb_UIType = new JLabel("界面类型：");
        jlb_UIType.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        startPanel.add(jlb_UIType);
        jcb_UIType = new ComboBox<>(Arrays.stream(ChessDTO.UI.values()).map(ChessDTO.UI::getName).toArray(String[]::new));
        jcb_UIType.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        startPanel.add(jcb_UIType);

        // 对战方式
        JLabel jlb_fightType = new JLabel("对战方式：");
        jlb_fightType.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        startPanel.add(jlb_fightType);
        jcb_fightType = new ComboBox<>(Arrays.stream(ChessCache.Battle.values()).filter(battle -> battle != ChessCache.Battle.PVC).map(ChessCache.Battle::getName).toArray(String[]::new));
        jcb_fightType.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        startPanel.add(jcb_fightType);

        // 选择颜色，且红方先手
        JLabel jlb_playFirst = new JLabel("玩家选择：");
        jlb_playFirst.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        startPanel.add(jlb_playFirst);
        jcb_playFirst = new ComboBox<>(Arrays.stream(ChessCache.Player.values()).map(ChessCache.Player::getName).toArray(String[]::new));
        jcb_playFirst.setBackground(JBColor.WHITE);
        jcb_playFirst.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        startPanel.add(jcb_playFirst);

        // 开始游戏按钮
        JButton startGameButton = new JButton("开始游戏");
        // 离线对弈
        startGameButton.addActionListener(e -> startGame0(ChessCache.Mode.OFFLINE));

        startPanel.add(startGameButton);

        // 在线显示创建房间按钮
        if (DataCache.isOnline) {
            // 如果已经是登录状态，就显示创建房间按钮
            List<Integer> numsList = new ArrayList<>();
            numsList.add(2);
            startPanel.add(getCreateRoomButton(numsList));
        }

        // 退出按钮
        startPanel.add(getExitButton());
    }


    /**
     * 改变玩家信息
     *
     * @param body 消息体
     */
    private void changePlayer(ChessDTO body) {
        // 棋子信息对调
        body.setX(9 - body.getX());
        body.setY(8 - body.getY());
    }

    /**
     * 游戏结束按钮
     *
     * @return 游戏结束按钮
     */
    public JButton gameOverButton() {
        //棋子信息对调
        return getGameOverButton();
    }

    @Override
    public void playerLeft(User player) {
        // 玩家离开
        super.playerLeft(player);
        // 游戏未结束且状态已开始时，离开即投降
        if (!gamePanel.isGameOver && status > -1) {
            ChessDTO dto = new ChessDTO();
            dto.setOption(ChessDTO.Option.SURRENDER);
            handle(dto);
        }
    }

}
